<template>
  <div class="h5ve-container card" ref="container">
    <div class="h5ve-toolbar card-header p-0">
      <div class="btn-group" title="排版">
        <button
          class="btn btn-sm btn-bold"
          title="加粗"
          @click.prevent="onCmd('bold')"
        >
          <i class="bi bi-type-bold"></i>
        </button>
        <button
          class="btn btn-sm btn-underline"
          title="下划线"
          @click.prevent="onCmd('underline')"
        >
          <i class="bi bi-type-underline"></i>
        </button>
        <button
          class="btn btn-sm btn-italic"
          title="斜体"
          @click.prevent="onCmd('italic')"
        >
          <i class="bi bi-type-italic"></i>
        </button>
      </div>
      <div class="btn-group" title="工具">
        <button
          class="btn btn-sm btn-copy"
          title="复制"
          @click.prevent="onCmd('copy')"
        >
          <i class="bi bi-files"></i>
        </button>
        <button
          class="btn btn-sm btn-cut"
          title="剪切"
          @click.prevent="onCmd('cut')"
        >
          <i class="bi bi-scissors"></i>
        </button>
        <button
          class="btn btn-sm btn-select"
          title="全选"
          @click.prevent="onCmd('select')"
        >
          <i class="bi bi-check-all"></i>
        </button>
        <button
          class="btn btn-sm btn-delete"
          title="删除"
          @click.prevent="onCmd('delete')"
        >
          <i class="bi bi-trash"></i>
        </button>
      </div>
      <div class="btn-group" title="插入">
        <button
          class="btn btn-sm btn-picture"
          title="图片"
          @click.prevent="onCmd('picture')"
        >
          <i class="bi bi-image"></i>
        </button>
        <button
          class="btn btn-sm btn-table"
          title="表格"
          @click.prevent="onCmd('table')"
        >
          <i class="bi bi-table"></i>
        </button>
      </div>
      <div class="btn-group" title="HTML代码">
        <button
          class="btn btn-sm btn-html"
          title="HTML代码"
          @click.prevent="onCmd('html')"
        >
          <i class="bi bi-code"></i>
        </button>
        <button
          class="btn btn-sm btn-print"
          title="打印"
          @click.prevent="onCmd('print')"
        >
          <i class="bi bi-printer"></i>
        </button>
        <button
          class="btn btn-sm btn-preview"
          title="预览"
          @click.prevent="onCmd('preview')"
        >
          <i class="bi bi-eye"></i>
        </button>
        <button
          class="btn btn-sm btn-fullwindow"
          title="全屏"
          @click.prevent="onCmd('fullwindow')"
        >
          <i class="bi bi-arrows-fullscreen"></i>
        </button>
        <button
          class="btn btn-sm btn-fullscreen"
          title="满屏"
          @click.prevent="onCmd('fullscreen')"
        >
          <i class="bi bi-fullscreen"></i>
        </button>
      </div>
      <div class="btn-group" title="帮助">
        <button
          class="btn btn-sm btn-help"
          title="帮助"
          @click.prevent="onCmd('help')"
        >
          <i class="bi bi-question"></i>
        </button>
      </div>
    </div>
    <div class="h5ve-content card-body p-0">
      <iframe
        style="width: 100%; height: 100%"
        frameborder="0"
        ref="iframe"
      ></iframe>
      <textarea :name="name" class="d-none" v-model="content"></textarea>
    </div>
    <div class="h5ve-footer card-footer p-1">
      <div>0 字符</div>
    </div>
    <!-- table-dialog -->
    <div class="modal fade" ref="dlgTable">
      <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">插入表格</h5>
            <button
              type="button"
              class="btn-close"
              data-bs-dismiss="modal"
              aria-label="Close"
            ></button>
          </div>
          <div class="modal-body">
            <form ref="formTable">
              <div class="row mb-3">
                <label class="col-sm-2 col-form-label">行数</label>
                <div class="col-sm-10">
                  <input
                    type="number"
                    class="form-control"
                    name="rows"
                    value="1"
                    min="1"
                  />
                </div>
              </div>
              <div class="row mb-3">
                <label class="col-sm-2 col-form-label">列数</label>
                <div class="col-sm-10">
                  <input
                    type="number"
                    class="form-control"
                    name="cols"
                    value="1"
                    min="1"
                  />
                </div>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-bs-dismiss="modal"
            >
              取消
            </button>
            <button
              type="button"
              class="btn btn-primary"
              @click="onInsertTable()"
            >
              确定
            </button>
          </div>
        </div>
      </div>
    </div>
    <!-- picture-dialog -->
    <div class="modal fade" ref="dlgPicture">
      <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">插入图片</h5>
            <button
              type="button"
              class="btn-close"
              data-bs-dismiss="modal"
              aria-label="Close"
            ></button>
          </div>
          <div class="modal-body">
            <form ref="formPicture" class="h5vedlg-form">
              <div>
                <strong class="d-block mb-1">从本地上传</strong>
                <input type="file" ref="imageFile" accept="image/*" multiple />
              </div>
              <div class="h5vedlg-error"></div>
              <div class="mt-2">
                <strong class="d-block mb-1">图片地址</strong>
                <input type="text" ref="imageUrl" class="w-100" />
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-bs-dismiss="modal"
            >
              取消
            </button>
            <button
              type="button"
              class="btn btn-primary"
              @click="onInsertPicture($event)"
            >
              确定
            </button>
          </div>
        </div>
      </div>
    </div>
    <!-- help-dialog -->
    <div class="modal fade" ref="dlgHelp">
      <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">帮助</h5>
            <button
              type="button"
              class="btn-close"
              data-bs-dismiss="modal"
              aria-label="Close"
            ></button>
          </div>
          <div class="modal-body">
            ctrl+z: 撤销
            <br />
            ctrl+y: 重做
            <br />
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-bs-dismiss="modal"
            >
              确定
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "Editor",
  props: {
    name: {
      type: String,
      default: "",
    },
    value: {
      type: String,
      default: "",
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "100%",
    },
    uploaderUrl: {
      type: String,
      default: "/api/admin/uploader",
    },
  },
  watch: {
    value(val) {
      this.$refs.iframe.contentDocument.body.innerHTML = this.htmldecode(val);
    },
    content(val) {
      this.$emit("update:value", val);
      // this.value=val;
    },
  },
  data() {
    return {
      content: this.value,
      modalTable: null,
      modalPicture: null,
      modalHelp: null,
    };
  },
  methods: {
    onCmd(cmd) {
      let elIframe = this.$refs.iframe;
      let elContainer = this.$refs.container;
      let win = null;
      switch (cmd) {
        case "bold":
          // 加粗
          elIframe.contentDocument.execCommand("bold");
          break;
        case "underline":
          // 下划线
          elIframe.contentDocument.execCommand("underline");
          break;
        case "sc":
          // 删除线
          elIframe.contentDocument.execCommand("underline");
          break;
        case "italic":
          // 斜体
          elIframe.contentDocument.execCommand("italic");
          break;
        case "copy":
          // 复制
          elIframe.contentDocument.execCommand("copy");
          break;
        case "cut":
          // 剪切
          elIframe.contentDocument.execCommand("cut");
          break;
        case "select":
          // 全选
          elIframe.contentDocument.execCommand("selectAll");
          break;
        case "paste":
          // 粘贴
          alert(
            "该功能尚未支持! 请使用浏览器右键 [粘贴] 或者键盘快捷键 [ctrl+v]"
          );
          break;
        case "delete":
          // 删除选中的内容
          elIframe.contentDocument.execCommand("Delete");
          break;
        case "fonts":
          // 设置字体
          //改变选中区域的字体;
          // elIframe.execCommand("FontName", false, sFontName);
          //改变选中区域的字体大小;
          // elIframe.execCommand("FontSize", false, sSize | iSize);
          //设置前景颜色;
          // elIframe.execCommand("ForeColor", false, sColor);
          break;
        case "table":
          // 插入表格
          this.modalTable.show();
          break;
        case "picture":
          this.modalPicture.show();
          // 插入图片
          break;
        case "html":
          // HTML代码
          if (elIframe.contentDocument.body.dataset.isEspace == "0") {
            elIframe.contentDocument.body.innerHTML = this.htmldecode(
              elIframe.contentDocument.body.innerHTML
            );
            elIframe.contentDocument.body.dataset.isEspace = "1";
          } else {
            elIframe.contentDocument.body.innerHTML = this.htmlencode(
              elIframe.contentDocument.body.innerHTML
            );
            elIframe.contentDocument.body.dataset.isEspace = "0";
          }
          break;
        case "preview":
          // 预览（弹窗）
          win = window.open("", "_blank");
          win.focus();
          win.document.title = " 预览";
          win.document.body.innerHTML = elIframe.contentDocument.body.innerHTML;
          break;
        case "print":
          // 打印
          elIframe.contentDocument.execCommand("print");
          break;
        case "fullscreen":
          // 显示器全屏
          if (document.fullscreenElement) {
            document.exitFullscreen();
          } else {
            elContainer.requestFullscreen();
          }
          break;
        case "fullwindow":
          // 浏览器窗口全屏
          if (elContainer.style.position == "fixed") {
            elContainer.dataset.fullWindow = "0";
            elContainer.style.position = "static";
            elContainer.style.zIndex = 1;
          } else {
            elContainer.dataset.fullWindow = "1";
            elContainer.style.position = "fixed";
            elContainer.style.top = 0;
            elContainer.style.bottom = 0;
            elContainer.style.left = 0;
            elContainer.style.right = 0;
            elContainer.style.zIndex = 999;
          }
          break;
        case "help":
          // 帮助
          this.modalHelp.show();
          break;
        default:
          break;
      }
    },
    onInsertTable() {
      let formData = new FormData(this.$refs.formTable);
      let params = {
        cols: parseInt(formData.get("cols")),
        rows: parseInt(formData.get("rows")),
      };
      let html = "";
      for (let irow = 0; irow < params.rows; irow++) {
        html += "<tr>";
        for (let icol = 0; icol < params.cols; icol++) {
          html += "<td> </td>";
        }
        html += "</tr>";
      }
      html = '<table border="1">' + html + "</table>";
      this.insertHtml(html);
      this.modalTable.hide();
    },
    async onInsertPicture($event) {
      let imageUrl = this.$refs.imageUrl.value.trim();
      let files = this.$refs.imageFile.files;
      if (files.length > 0) {
        $event.target.innerText = "上传中...";
      }
      // 开启多文件上传功能，字段名称为 file[]，适用于 php 后端
      let images = [];
      if (imageUrl.length > 0) {
        images.push(imageUrl);
      }
      try {
        const msgInfo = await stdUploadFile(files, this.uploaderUrl);
        console.log("[可视化编辑器] 上传图片结果：", msgInfo);
        if (msgInfo.success) {
          let list = msgInfo.data.split(",");
          list.forEach((v) => {
            images.push(v);
          });
        } else {
          alert("出错啦：" + msgInfo.message);
        }
      } catch (error) {
        alert("上传错误：" + error.message);
        console.log("[可视化编辑器] 上传图片异常", error);
      }

      let html =
        '<img src="' +
        images.join('" alt="" /><br /><img src="') +
        '" alt="" />';
      console.log("[可视化编辑器] 插入图片 html=", html);
      this.insertHtml(html);
      this.modalPicture.hide();
    },
    // 在当前光标位置插入内容
    insertHtml(html) {
      let selection = this.$refs.iframe.contentWindow.getSelection();
      if (selection.rangeCount > 0) {
        let range = selection.getRangeAt(0);
        range.collapse(false);
        let documentFragment = range.createContextualFragment(html);
        range.insertNode(documentFragment);
      } else {
        this.$refs.iframe.contentDocument.body.innerHTML += html;
      }
    },
    htmlencode(html) {
      return html
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
    },
    htmldecode(text) {
      return text
        .replace(/&lt;/g, "<")
        .replace(/&gt;/g, ">")
        .replace(/&quot;/g, '"')
        .replace(/&amp;/g, "&");
    },
  },
  mounted() {
    this.modalTable = new bootstrap.Modal(this.$refs.dlgTable, {});
    this.modalPicture = new bootstrap.Modal(this.$refs.dlgPicture, {});
    this.modalHelp = new bootstrap.Modal(this.$refs.dlgHelp, {});
    this.$refs.iframe.contentDocument.designMode = "on";
    // 监听文档内容的变化
    new MutationObserver((mutationsList, observer) => {
      console.log("[H5VisiualEditor] mutationsList=", mutationsList);
      console.log("[H5VisiualEditor] observer=", observer);
      this.content = this.htmlencode(
        this.$refs.iframe.contentDocument.body.innerHTML
      );
    }).observe(this.$refs.iframe.contentDocument.body, {
      attributes: true, // 修改目标节点属性时会收到通知
      childList: true, // childList：添加、删除目标节点的子节点时会收到通知（子节点的后代节点添加或删除时不会收到通知）
      subtree: true, // 目标节点或后代节点变更时都会触发，必须配合其他属性一起使用
      attributeOldValue: true, // 表示需要记录改变前的目标属性值，设置了attributeOldValue可以省略attributes设置
      characterData: true, // 观察目标节点下所有文本类型节点（即子代或后代）的文字变化（注意：添加、删除文本节点不会被观察到，如果改变之前的类型不是文本节点也不会被观察到），该属性只能配合subtree使用。
    });
  },
};
</script>

<style>
</style>